package com.tmt.im.service.controller;

import com.alibaba.fastjson2.JSONObject;
import com.tmt.im.service.controller.vo.*;
import com.tmt.im.service.helper.PrincipalHelper;
import com.tmt.im.service.interfaces.ISessionMemberManager;
import com.tmt.springboot.common.restful.ExecuteResult;
import com.tmt.springboot.common.restful.IExecuteResult;
import com.tmt.springboot.common.restful.ResultWrapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteSemaphore;
import org.springframework.scheduling.annotation.Async;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;
import java.text.MessageFormat;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * @Description TODO
 * @Author wuyi
 * @Date 2024/8/30 15:12
 * @Version 1.0
 **/
@Slf4j
@Tag(name = "群组成员相关接口", description = "群组成员相关接口")
@RestController
@RequestMapping("${api-url-prefix}/member")
@Async("asyncTaskExecutor")
public class SessionMemberController {

    private Ignite ignite;

    private final ISessionMemberManager iSessionMemberManager;

    public SessionMemberController(Ignite ignite, ISessionMemberManager iSessionMemberManager) {
        this.ignite = ignite;
        this.iSessionMemberManager = iSessionMemberManager;
    }

    @Operation(summary = "拉人入群",
            description = "拉人入群",
            operationId = "joinSession",
            parameters = {
                    @Parameter(name = "request", description = "拉人入群请求对象", required = true)
            })
    @PostMapping("/join")
    public CompletableFuture<IExecuteResult<JoinSessionResponse>> joinSession(@RequestBody @Validated JoinSessionRequest request, Principal principal) {
        try (IgniteSemaphore semaphore = ignite.semaphore(
                MessageFormat.format("joinSession_{0}", "" + request.getTid()), // Distributed semaphore name.
                1,        // Number of permits.
                true,      // Release acquired permits if node, that owned them, left topology.
                true       // Create if it doesn't exist.
        )) {
            if (semaphore.tryAcquire(3, TimeUnit.SECONDS)) {
                try {
                    StringBuilder error = new StringBuilder();
                    Long currentUserId = PrincipalHelper.getCurrentUserId(principal);
                    assert currentUserId != null;
                    JoinSessionResponse result = iSessionMemberManager.joinSession(currentUserId, request, principal, error);
                    return CompletableFuture.completedFuture(result != null ? ExecuteResult.success(result)
                            : ExecuteResult.failure(error.toString(), null));
                } catch (Exception ex) {
                    return CompletableFuture.completedFuture(ExecuteResult.failure(ex.getMessage(), null));
                }
            } else {
                return CompletableFuture.completedFuture(ExecuteResult.failure("系统繁忙，请稍后再试", null));
            }
        } catch (Exception ex) {
            return CompletableFuture.completedFuture(ExecuteResult.failure("获取全局信号量异常：" + ex.getMessage(), null));
        }
    }

    @Operation(summary = "待审入群邀请列表查询接口",
            description = "待审入群邀请列表查询接口",
            operationId = "listInvitation",
            parameters = {
                    @Parameter(name = "tid", description = "群组ID, 允许为null"),
                    @Parameter(name = "pageIndex", description = "页序号，从0开始", required = true),
                    @Parameter(name = "pageSize", description = "页尺寸,默认值20")
            })
    @GetMapping("/invitation/list")
    public CompletableFuture<IExecuteResult<WaitingCheckInvitationResponse>> listInvitation(@RequestParam(value = "tid", required = false) Long tid,
                                                                                            @RequestParam("pageIndex") int pageIndex,
                                                                                            @RequestParam(value = "pageSize", defaultValue = "20", required = false) int pageSize,
                                                                                            Principal principal) {
        Long currentUserId = PrincipalHelper.getCurrentUserId(principal);
        assert currentUserId != null;
        StringBuilder error = new StringBuilder();
        WaitingCheckInvitationResponse result = iSessionMemberManager.listInvitation(
                currentUserId, tid, pageIndex, pageSize, principal, error);
        return CompletableFuture.completedFuture(result != null ? ExecuteResult.success(result)
                : ExecuteResult.failure(error.toString(), null));
    }

    @Operation(summary = "群主或管理员审核入群邀请",
            description = "群主或管理员审核入群邀请",
            operationId = "reviewInvitation",
            parameters = {
                    @Parameter(name = "reply", description = "群主或管理员审核入群邀请", required = true)
            })
    @PostMapping("/invitation/review")
    public CompletableFuture<IExecuteResult<ResultWrapper<Boolean>>> reviewInvitation(@RequestBody JoiningSessionReply reply, Principal principal) {
        try (IgniteSemaphore semaphore = ignite.semaphore(
                MessageFormat.format("reviewInvitation_{0}", reply.getApplyId()), // Distributed semaphore name.
                1,        // Number of permits.
                true,      // Release acquired permits if node, that owned them, left topology.
                true       // Create if it doesn't exist.
        )) {
            if (semaphore.tryAcquire(3, TimeUnit.SECONDS)) {
                try {
                    StringBuilder error = new StringBuilder();
                    Long currentUserId = PrincipalHelper.getCurrentUserId(principal);
                    assert currentUserId != null;

                    boolean result = iSessionMemberManager.reviewInvitation(currentUserId, reply, principal, error);
                    return CompletableFuture.completedFuture(result ? ResultWrapper.from(ExecuteResult.success(true))
                            : ResultWrapper.from(ExecuteResult.failure(error.toString(), false)));
                } catch (Exception ex) {
                    return CompletableFuture.completedFuture(ExecuteResult.failure(ex.getMessage(), null));
                }
            } else {
                return CompletableFuture.completedFuture(ExecuteResult.failure("系统繁忙，请稍后再试", null));
            }
        } catch (Exception ex) {
            return CompletableFuture.completedFuture(ExecuteResult.failure("获取全局信号量异常：" + ex.getMessage(), null));
        }
    }

    @Operation(summary = "被邀请人同意或拒绝入群",
            description = "被邀请人同意或拒绝入群",
            operationId = "replyInvitation",
            parameters = {
                    @Parameter(name = "reply", description = "被邀请人对入群邀请的回复对象", required = true)
            })
    @PostMapping("/invitation/reply")
    public CompletableFuture<IExecuteResult<ResultWrapper<Boolean>>> replyInvitation(@RequestBody JoiningSessionReply reply, Principal principal) {
        try (IgniteSemaphore semaphore = ignite.semaphore(
                MessageFormat.format("replyInvitation_{0}", reply.getApplyId()), // Distributed semaphore name.
                1,        // Number of permits.
                true,      // Release acquired permits if node, that owned them, left topology.
                true       // Create if it doesn't exist.
        )) {
            if (semaphore.tryAcquire(3, TimeUnit.SECONDS)) {
                try {
                    StringBuilder error = new StringBuilder();
                    Long currentUserId = PrincipalHelper.getCurrentUserId(principal);
                    assert currentUserId != null;
                    boolean result = iSessionMemberManager.replyInvitation(currentUserId, reply, principal, error);
                    return CompletableFuture.completedFuture(result ? ResultWrapper.from(ExecuteResult.success(true))
                            : ResultWrapper.from(ExecuteResult.failure(error.toString(), false)));
                } catch (Exception ex) {
                    return CompletableFuture.completedFuture(ExecuteResult.failure(ex.getMessage(), null));
                }
            } else {
                return CompletableFuture.completedFuture(ExecuteResult.failure("系统繁忙，请稍后再试", null));
            }
        } catch (Exception ex) {
            return CompletableFuture.completedFuture(ExecuteResult.failure("获取全局信号量异常：" + ex.getMessage(), null));
        }
    }

    @Operation(summary = "踢出群组",
            description = "踢出群组",
            operationId = "kickOutSession",
            parameters = {
                    @Parameter(name = "request", description = "踢出群组请求对象", required = true)
            })
    @PostMapping("/kickOut")
    public CompletableFuture<IExecuteResult<KickOutSessionResponse>> kickOutSession(@RequestBody @Validated KickOutSessionRequest request, Principal principal) {
        try (IgniteSemaphore semaphore = ignite.semaphore(
                MessageFormat.format("kickOutSession_{0}", request.getTid()), // Distributed semaphore name.
                1,        // Number of permits.
                true,      // Release acquired permits if node, that owned them, left topology.
                true       // Create if it doesn't exist.
        )) {
            if (semaphore.tryAcquire(3, TimeUnit.SECONDS)) {
                try {
                    StringBuilder error = new StringBuilder();
                    Long currentUserId = PrincipalHelper.getCurrentUserId(principal);
                    KickOutSessionResponse result = iSessionMemberManager.kickOutSession(currentUserId, request, principal, error);
                    return CompletableFuture.completedFuture(result != null ? ExecuteResult.success(result)
                            : ExecuteResult.failure(error.toString(), null));
                } catch (Exception ex) {
                    return CompletableFuture.completedFuture(ExecuteResult.failure(ex.getMessage(), null));
                }
            } else {
                return CompletableFuture.completedFuture(ExecuteResult.failure("系统繁忙，请稍后再试", null));
            }
        } catch (Exception ex) {
            return CompletableFuture.completedFuture(ExecuteResult.failure("获取全局信号量异常：" + ex.getMessage(), null));
        }
    }

    @Operation(summary = "主动退群",
            description = "主动退群",
            operationId = "leaveSession",
            parameters = {
                    @Parameter(name = "tid", description = "主动退群请求对象", required = true)
            })
    @PostMapping("/leave")
    public CompletableFuture<IExecuteResult<ResultWrapper<Boolean>>> leaveSession(@RequestParam("tid") Long tid, Principal principal) {
        Long currentUserId = PrincipalHelper.getCurrentUserId(principal);
        try (IgniteSemaphore semaphore = ignite.semaphore(
                MessageFormat.format("leaveSession_{0}_{1}", "" + tid, "" + currentUserId), // Distributed semaphore name.
                1,        // Number of permits.
                true,      // Release acquired permits if node, that owned them, left topology.
                true       // Create if it doesn't exist.
        )) {
            if (semaphore.tryAcquire(3, TimeUnit.SECONDS)) {
                try {
                    StringBuilder error = new StringBuilder();
                    boolean result = iSessionMemberManager.leaveSession(currentUserId, tid, principal, error);
                    return CompletableFuture.completedFuture(result ? ResultWrapper.from(ExecuteResult.success(true))
                            : ResultWrapper.from(ExecuteResult.failure(error.toString(), false)));
                } catch (Exception ex) {
                    return CompletableFuture.completedFuture(ExecuteResult.failure(ex.getMessage(), null));
                }
            } else {
                return CompletableFuture.completedFuture(ExecuteResult.failure("系统繁忙，请稍后再试", null));
            }
        } catch (Exception ex) {
            return CompletableFuture.completedFuture(ExecuteResult.failure("获取全局信号量异常：" + ex.getMessage(), null));
        }
    }

    @Operation(summary = "主动退群扩展接口",
            description = "主动退群，使用JSON对象接收传入的参数",
            operationId = "leaveSession",
            parameters = {
                    @Parameter(name = "param", description = "传入参数的JSON对象", required = true)
            })
    @PostMapping("/leave/json")
    public CompletableFuture<IExecuteResult<ResultWrapper<Boolean>>> leaveSession(@RequestBody JSONObject param, Principal principal) {
        Long tid = param.getLong("tid");
        if (tid == null) {
            IExecuteResult<Boolean> result = ExecuteResult.failure("群组ID(tid)参数不能为空", false);
            return CompletableFuture.completedFuture(ResultWrapper.from(result));
        }
        return leaveSession(tid, principal);
    }

    @Operation(summary = "允许或禁止群成员抢手气红包",
            description = "允许或禁止群成员抢手气红包",
            operationId = "updateForbidRedPackage",
            parameters = {
                    @Parameter(name = "request", description = "更新群成员抢红包控制参数请求对象", required = true)
            })
    @PostMapping("/redPackage")
    public CompletableFuture<IExecuteResult<ResultWrapper<Boolean>>> updateForbidRedPackage(@RequestBody @Validated UpdateForbidRedPackageRequest request,
                                                                                            Principal principal) {
        StringBuilder error = new StringBuilder();
        Long currentUserId = PrincipalHelper.getCurrentUserId(principal);
        IExecuteResult<Boolean> result = iSessionMemberManager.updateForbidRedPackage(currentUserId, request, principal, error);
        return CompletableFuture.completedFuture(ResultWrapper.from(result));
    }

    @Operation(summary = "更新群成员昵称",
            description = "更新群成员昵称",
            operationId = "updateMemberNick",
            parameters = {
                    @Parameter(name = "request", description = "更新群成员昵称请求对象", required = true)
            })
    @PostMapping("/update/nick")
    public CompletableFuture<IExecuteResult<ResultWrapper<Boolean>>> updateMemberNick(@RequestBody @Validated UpdateMemberNickRequest request, Principal principal) {
        StringBuilder error = new StringBuilder();
        Long currentUserId = PrincipalHelper.getCurrentUserId(principal);
        IExecuteResult<Boolean> result = iSessionMemberManager.updateMemberNick(currentUserId, request, principal, error);
        return CompletableFuture.completedFuture(ResultWrapper.from(result));
    }

    @Operation(summary = "群成员禁言",
            description = "群成员禁言",
            operationId = "bannedMembers",
            parameters = {
                    @Parameter(name = "request", description = "群成员禁言请求对象", required = true)
            })
    @PostMapping("/banned")
    public CompletableFuture<IExecuteResult<ChatBannedResponse>> bannedMembers(@RequestBody @Validated ChatBannedRequest request, Principal principal) {
        StringBuilder error = new StringBuilder();
        Long currentUserId = PrincipalHelper.getCurrentUserId(principal);
        IExecuteResult<ChatBannedResponse> result = iSessionMemberManager.bannedMembers(currentUserId, request, principal, error);
        return CompletableFuture.completedFuture(result);
    }

    @Operation(summary = "设置群消息免打扰",
            description = "开启或关闭群消息免打扰功能",
            operationId = "noDisturbingMember",
            parameters = {
                    @Parameter(name = "request", description = "群消息免打扰请求对象", required = true)
            })
    @PostMapping("/noDisturbing")
    public CompletableFuture<IExecuteResult<ResultWrapper<Boolean>>> noDisturbingMember(@RequestBody @Validated NoDisturbingRequest request, Principal principal) {
        StringBuilder error = new StringBuilder();
        Long currentUserId = PrincipalHelper.getCurrentUserId(principal);
        IExecuteResult<Boolean> result = iSessionMemberManager.noDisturbingMember(currentUserId, request, principal, error);
        return CompletableFuture.completedFuture(ResultWrapper.from(result));
    }

    @Operation(summary = "获取当前用户加入的所有聊天群组列表",
            description = "获取当前用户加入的所有聊天群组列表",
            operationId = "getAllSession")
    @GetMapping("/getAllSession")
    public CompletableFuture<IExecuteResult<List<ChatSessionDetailVo>>> getAllSession(Principal principal) {
        //创建聊天会话。
        StringBuilder error = new StringBuilder();
        Long currentUserId = PrincipalHelper.getCurrentUserId(principal);
        List<ChatSessionDetailVo> result = iSessionMemberManager.getAllSession(currentUserId, error);
        return CompletableFuture.completedFuture(result != null ? ExecuteResult.success(result)
                : ExecuteResult.failure(error.toString(), null));
    }


}
